import os
import time

import numpy as np
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox
from matplotlib import pyplot as plt
import matplotlib.dates as mdates
from GuiWindows import *
from BaseFunction import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

plt.rc("font", family='Microsoft YaHei')
_translate = QtCore.QCoreApplication.translate


class MyApp(QMainWindow, Ui_Form):
    def __init__(self):
        super().__init__()
        self.setupUi(self)  # 初始化界面
        # 数据输入
        self.pushButton.clicked.connect(self.get_xlsx_path)
        self.pushButton_3.clicked.connect(self.get_data_path)
        self.comboBox.currentIndexChanged.connect(self.select_satellite_file)
        self.comboBox_2.currentIndexChanged.connect(self.select_sat)
        self.pushButton_2.clicked.connect(self.read_all_data)
        self.xlsx_data_path = None
        self.xlsx_data = None
        self.real_time = None
        self.real_high = None
        self.satellite_data_path = None
        self.satellite_all_data = None
        self.satellite_data = None
        self.all_wave_length = {'L1': 0.1903, 'L2': 0.2442, 'L5': 0.2548,
                                'R1': 0.1871, 'R2': 0.2402, 'B1': 0.1920,
                                'B6': 0.2483, 'B7': 0.2364, 'E1': 0.1902,
                                'E5': 0.2548, 'E7': 0.2483, 'E8': 0.2517}
        # 参数设置
        self.lineEdit_7.editingFinished.connect(lambda: get_edit_figure(self, 'azl'))
        self.lineEdit_8.editingFinished.connect(lambda: get_edit_figure(self, 'azh'))
        self.lineEdit_9.editingFinished.connect(lambda: get_edit_figure(self, 'ell'))
        self.lineEdit_10.editingFinished.connect(lambda: get_edit_figure(self, 'elh'))
        self.lineEdit_11.editingFinished.connect(lambda: get_edit_figure(self, 'ath'))
        self.az_range = [-60., 105.]
        self.el_range = [4., 9.]
        self.ant_high = 7.797

        # 质量控制
        self.lineEdit_17.editingFinished.connect(lambda: get_edit_figure(self, 'mns'))
        self.lineEdit_19.editingFinished.connect(lambda: get_edit_figure(self, 'pks'))
        self.lineEdit_20.editingFinished.connect(lambda: get_edit_figure(self, 'amp'))
        self.lineEdit_13.editingFinished.connect(lambda: get_edit_figure(self, 'vhl'))
        self.lineEdit_14.editingFinished.connect(lambda: get_edit_figure(self, 'vhh'))
        # self.comboBox_3.activated.connect(self.select_decomposition_method)
        self.min_snr = 25.
        self.peak_snr = 3.
        self.amplitude = 3.
        self.valid_high = [4., 8.]
        self.decomposition_method = "低阶二次拟合"
        self.param1 = 1
        self.param2 = 1
        self.param3 = 1

        # 质量分析
        self.pushButton_10.clicked.connect(self.inverse_analysis)
        # self.pushButton_4.clicked.connect(self.fresnel_reflection_draw)
        self.pushButton_6.clicked.connect(self.reflected_signal_display)
        self.pushButton_8.clicked.connect(self.spectral_analysis_display)
        self.pushButton_5.clicked.connect(self.inversion_results_display)
        self.pushButton_7.clicked.connect(self.residual_error_display)
        self.pushButton_9.clicked.connect(self.fused_computing)
        self.result = None
        self.all_result = []
        self.mae = []
        self.rmse = []
        self.r = []

        # 图像绘制
        self.figure1 = Figure(figsize=(5, 5), dpi=100)
        self.canvas1 = FigureCanvas(self.figure1)
        layout1 = QtWidgets.QVBoxLayout(self.widget)
        layout1.setContentsMargins(2, 2, 2, 2)
        layout1.addWidget(self.canvas1)

        self.figure2 = Figure(figsize=(5, 5), dpi=100)
        self.canvas2 = FigureCanvas(self.figure2)
        layout1 = QtWidgets.QVBoxLayout(self.widget_2)
        layout1.setContentsMargins(2, 2, 2, 2)
        layout1.addWidget(self.canvas2)

        self.figure3 = Figure(figsize=(5, 5), dpi=100)
        self.canvas3 = FigureCanvas(self.figure3)
        layout1 = QtWidgets.QVBoxLayout(self.widget_3)
        layout1.setContentsMargins(2, 2, 2, 2)
        layout1.addWidget(self.canvas3)

    def get_xlsx_path(self):
        self.xlsx_data_path = get_file_name()
        name = self.xlsx_data_path.split('/')[-1]
        self.label_5.setText(_translate("Form", name))

    def get_data_path(self):
        self.satellite_data_path = get_directory()
        name = self.satellite_data_path.split('/')[-1]
        self.label_23.setText(_translate("Form", name))

    def select_satellite_file(self):
        self.result = None
        if self.satellite_data_path is None:
            self.comboBox.setItemText(0, _translate("Form", "卫星波段"))
            QMessageBox.warning(self, "错误", "请选择卫星数据文件夹")
            return False
        files = os.listdir(self.satellite_data_path)
        label = self.comboBox.currentText()
        if label == "卫星波段":
            self.comboBox_2.clear()
            self.comboBox_2.addItem(_translate("Form", "卫星数据"))
            return False
        self.label_4.setText(_translate("Form", str(self.all_wave_length[label])))
        select_files = []
        for file in files:
            if get_satellite_label(file, label):
                select_files.append(file)
        if len(select_files) == 0:
            self.comboBox.setItemText(0, _translate("Form", "卫星波段"))
            self.label_4.setText(_translate("Form", "未选择卫星数据"))
            self.comboBox_2.clear()
            self.comboBox_2.addItem(_translate("Form", "卫星数据"))
            QMessageBox.warning(self, "错误", "波段不存在")
            return False
        self.satellite_all_data = pd.concat(
            [read_satellite_data(self.satellite_data_path + '/' + file) for file in select_files],
            ignore_index=True  # 重置索引，避免重复
        )
        try:
            satellite_data = read_satellite_data(self.satellite_data_path + '/' + select_files[0])
            sats = list(satellite_data['SAT'].value_counts().sort_index().index)
            self.comboBox_2.clear()
            self.comboBox_2.addItem(_translate("Form", "ALL"))
            for sat in sats:
                self.comboBox_2.addItem(_translate("Form", sat))
        except:
            self.label_23.setText(_translate("Form", '文件夹名称'))
            self.comboBox_2.clear()
            self.comboBox_2.addItem(_translate("Form", "卫星数据"))
            QMessageBox.warning(self, "错误", "请选择正确的卫星数据")
            return False
        return True

    def select_sat(self):
        try:
            sat = self.comboBox_2.currentText()
            if sat != 'ALL':
                self.satellite_data = self.satellite_all_data[self.satellite_all_data["SAT"] == sat]
            else:
                self.satellite_data = self.satellite_all_data
        except:
            QMessageBox.warning(self, "错误", "请选择正确的卫星数据")
            return False
        return True

    def read_all_data(self):
        try:
            xlsx_start = self.lineEdit_3.text()
            xlsx_end = self.lineEdit_2.text()
            self.xlsx_data = read_excel_range(self.xlsx_data_path, xlsx_start + ':' + xlsx_end)
            real_time = [t[0] for t in self.xlsx_data]
            real_high = [h[1] for h in self.xlsx_data]
            self.real_time, self.real_high = interpolate_time_series(real_time, real_high)
        except:
            self.label_5.setText(_translate("Form", "文件名称"))
            QMessageBox.warning(self, "错误", "请选择正确的水位数据")
            return False

        try:
            ax = self.figure1.add_subplot(111)
            # img = plt.imread('HKQT.jpg')
            img = plt.imread('NASS.jpg')
            ax.imshow(img)
            ax.set_title('站点位置')
            self.canvas1.draw()
            QApplication.processEvents()
        except:
            QMessageBox.warning(self, "错误", "未找到站点位置图像HKQT.jpg")
            return False
        try:
            sats = list(self.satellite_data['SAT'].value_counts().sort_index().index)
            self.figure2.clear()
            self.figure3.clear()
            ax2 = self.figure2.add_subplot(111)
            ax2.set_title('SNR图像')
            ax2.set_ylabel('SNR (dB-Hz)')
            ax2.grid(True, linestyle='--', alpha=0.5)

            ax3 = self.figure3.add_subplot(111)
            ax3.set_title('高度角图像')
            ax3.set_ylabel('高度角 (°)')
            ax3.grid(True, linestyle='--', alpha=0.5)
            for sat in sats:
                color = np.random.rand(3)
                data = self.satellite_data[self.satellite_data["SAT"] == sat]
                data = data.drop_duplicates(subset=['TIME'], keep='first')
                times = pd.to_datetime(data['TIME'])  # 转换为 datetime 格式
                snr = data['SNR']
                el = data['EL']
                ax2.scatter(
                    times,  # X轴: 时间
                    snr,  # Y轴: SNR
                    color=color,  # 随机颜色
                    alpha=0.7,  # 透明度
                    s=1  # 点大小
                )
                ax3.scatter(
                    times,  # X轴: 时间
                    el,  # Y轴: EL
                    color=color,  # 随机颜色
                    alpha=0.7,  # 透明度
                    s=1  # 点大小
                )
                ax2.xaxis.set_major_formatter(mdates.DateFormatter("%m月%d日"))
                ax2.xaxis.set_major_locator(mdates.DayLocator(interval=1))
                ax3.xaxis.set_major_formatter(mdates.DateFormatter("%m月%d日"))
                ax3.xaxis.set_major_locator(mdates.DayLocator(interval=1))
                self.canvas2.draw()
                self.canvas3.draw()
                QApplication.processEvents()
        except:
            QMessageBox.warning(self, "错误", "卫星数据解析失败")
            return False
        return True

    def select_decomposition_method(self):
        txt = self.comboBox_3.currentText()
        # txt = "低阶二次拟合"
        self.decomposition_method = txt
        if txt == '小波分析':
            dialog = InputDialog("参数设置")
            if dialog.exec_() == QtWidgets.QDialog.Accepted:
                self.param1, self.param2, self.param3 = dialog.get_inputs()

    def inverse_analysis(self):
        self.decomposition_method = "低阶二次拟合"
        try:
            self.label_27.setText(_translate("Form", "未计算"))
            self.label_28.setText(_translate("Form", "未计算"))
            self.label_29.setText(_translate("Form", "未计算"))
            method = {"低阶二次拟合": 1, "EMD": 2, "小波分析": 3}
            params = {
                'ele_s': self.el_range[0], 'ele_d': self.el_range[1],
                'azi_s': self.az_range[0], 'azi_d': self.az_range[1],
                'Ant_h': self.ant_high,
                'data_num': self.min_snr,
                'L_r': self.all_wave_length[self.comboBox.currentText()],  # GPS L1波长
                'zqb_s': self.amplitude,
                'peak_s': self.peak_snr / 10,
                'h_s': self.valid_high[0], 'h_d': self.valid_high[1],
                'method': method[self.decomposition_method],
                'p1': int(self.param1),
                'p2': int(self.param2),
                'p3': int(self.param3)
            }
            self.result = gnss_height_inversion(self.satellite_data.copy(), params)
            self.all_result.append(self.result)
            QMessageBox.information(self, "提示", "反演计算完成！", QMessageBox.Ok)
        except:
            QMessageBox.warning(self, "错误", "反演失败")

    def fresnel_reflection_draw(self):
        try:
            self.figure2.clear()
            self.canvas2.draw()
            QApplication.processEvents()

            ax = self.figure2.add_subplot(111)
            ax.set_title('菲涅尔反射区')
            ax.set_aspect('equal')
            ax.set_xlabel('East (m)', fontsize=9)
            ax.set_ylabel('North (m)', fontsize=9)
            ax.grid(True, linestyle='--', alpha=0.6)
            ax.grid(True, which='minor', linestyle=':', alpha=0.4)

            df = preprocess_satellite_data(self.satellite_data.copy())
            el_list = list(range(int(self.el_range[0]), int(self.el_range[1]) + 1))

            colors = plt.cm.hsv(np.linspace(0, 0.8, len(el_list)))
            unique_az = df['AZ'].dropna().unique()
            for az in unique_az:
                for idx, el in enumerate(el_list):
                    try:
                        A, B, R = fresnel_zone(1, el, self.ant_high, az)

                        # 生成椭圆基础点
                        x = np.arange(-A, A + 0.1, 0.1)  # 0.1米步长
                        y_upper = B * np.sqrt(1 - (x ** 2) / (A ** 2))
                        y_lower = -y_upper

                        # 组合上下半圆（翻转顺序）
                        x_full = np.concatenate([x, np.flip(x)])
                        y_full = np.concatenate([y_upper, np.flip(y_lower)])

                        # 应用MATLAB坐标变换
                        x_trans = -(x_full - R)  # geez2 = -(x - Ctr)
                        y_trans = y_full  # geez1 = y

                        # 构建旋转矩阵（北顺时针转matplotlib的东逆时针）
                        theta_rad = math.radians(-az)  # 处理方向差异
                        rot_matrix = np.array([
                            [math.cos(theta_rad), math.sin(theta_rad)],
                            [-math.sin(theta_rad), math.cos(theta_rad)]
                        ])

                        # 执行旋转
                        points = np.vstack([y_trans, x_trans]).T
                        rotated = np.dot(points, rot_matrix)

                        # 绘制（修正Y轴方向）
                        ax.plot(rotated[:, 0], rotated[:, 1],
                                color=colors[idx],
                                linewidth=2,
                                linestyle='-')
                        legend_labels = [f'EL {el}°' for el in el_list]
                        ax.legend(legend_labels,
                                  loc='upper right', fontsize=8)
                        self.canvas2.draw()
                        QApplication.processEvents()
                    except Exception as e:
                        print(f"跳过无效组合：方位角{az:.1f}° 高度角{el}° | 错误：{str(e)}")
                        continue
        except:
            QMessageBox.warning(self, "错误", "未选择卫星数据")

    def reflected_signal_display(self):
        try:
            self.figure3.clear()
            self.canvas3.draw()
            QApplication.processEvents()
            ax = self.figure3.add_subplot(111)
            ax.set_title('反射信号图')
            ax.set_xlabel('sin(Elevation angle)', fontsize=9)
            ax.set_ylabel('SNR (V)', fontsize=9)
            ax.grid(True, linestyle='--', alpha=0.6)
            for i in range(len(self.result['rightf'])):
                y1 = self.result['frp2'][i]
                detrend = self.result['frp6'][i]
                ax.plot(y1, detrend, '-', color=np.random.rand(3, ))
                self.canvas3.draw()
                QApplication.processEvents()
        except:
            QMessageBox.warning(self, "错误", "未进行反演")

    def spectral_analysis_display(self):
        try:
            self.figure2.clear()
            self.canvas2.draw()
            QApplication.processEvents()
            ax = self.figure2.add_subplot(111)
            ax.set_title('L-S谱分析图')
            ax.set_xlim(0, 100)
            ax.set_ylim(0, 20)
            ax.set_xlabel('频率')
            ax.set_ylabel('振幅 (V)')
            ax.grid(True)
            line1 = plt.Line2D([0], [0], color='gray', lw=1, label='频率变化')
            line2 = plt.Line2D([0], [0], marker='o', fillstyle='none', color='red', linestyle='', label='峰值功率')
            ax.legend(loc='upper left', handles=[line1, line2])
            for i in range(len(self.result['rightf'])):
                frp = self.result['frp1'][i]
                color = np.random.rand(3)
                ax.plot(frp[:, 0], frp[:, 1],
                        '-', linewidth=1, color=color,
                        )
                ax.plot(self.result['rightf'][i], self.result['mpeak'][i],
                        marker='o', fillstyle='none', color=color,
                        )
                self.canvas2.draw()
                QApplication.processEvents()
        except:
            QMessageBox.warning(self, "错误", "未进行反演")

    def inversion_results_display(self):
        try:
            self.figure3.clear()
            self.canvas3.draw()
            QApplication.processEvents()
            inversion_time = [t[0].replace(second=0) for t in self.result['bbb1']]
            inversion_high = [h[2] for h in self.result['bbb1']]
            ax = self.figure3.add_subplot(111)
            ax.set_title('海平面高度反演结果图')
            ax.set_xlabel('时间')
            ax.xaxis.set_major_formatter(mdates.DateFormatter("%m月%d日"))
            ax.xaxis.set_major_locator(mdates.DayLocator(interval=1))
            ax.set_ylabel('潮位 (m)')
            ax.grid(True)
            line1 = plt.Line2D([0], [0], color='gray', lw=1, label='真实潮位')
            line2 = plt.Line2D([0], [0], marker='$\u2605$', color='red', linestyle='', label='反演潮位')
            ax.legend(loc='upper left', handles=[line1, line2])
            ax.plot(self.real_time, self.real_high, '-', color=np.random.rand(3, ))
            for i in range(len(inversion_time)):
                ax.plot(inversion_time[i], inversion_high[i], marker='$\u2605$', color='red', markersize=5)
                self.canvas3.draw()
                QApplication.processEvents()
        except:
            QMessageBox.warning(self, "错误", "未进行反演")

    def residual_error_display(self):
        try:
            self.figure2.clear()
            self.canvas2.draw()
            QApplication.processEvents()

            inversion_time = [t[0].replace(second=0) for t in self.result['bbb1']]
            inversion_high = [h[2] for h in self.result['bbb1']]
            mapping = dict(zip(self.real_time, self.real_high))
            real_high = [mapping[x] for x in inversion_time]
            dealt_high = [abs(h1 - h2) for h1, h2 in zip(inversion_high, real_high)]
            inversion_high = np.asarray(inversion_high).flatten()
            real_high = np.asarray(real_high).flatten()
            mae = mean_absolute_error(inversion_high, real_high)
            self.mae.append(mae)
            rmse = np.sqrt(mean_squared_error(inversion_high, real_high))
            self.rmse.append(rmse)
            r, _ = pearsonr(inversion_high, real_high)
            self.r.append(r)

            self.label_27.setText(_translate("Form", "{:.3f}".format(mae)))
            self.label_28.setText(_translate("Form", "{:.3f}".format(rmse)))
            self.label_29.setText(_translate("Form", "{:.3f}".format(r)))

            ax = self.figure2.add_subplot(111)
            ax.set_title('残差序列图')
            ax.set_xlabel('时间')
            ax.set_ylabel('绝对误差')
            ax.grid(True)
            ax.scatter(inversion_time, dealt_high, color='red', s=10)
            ax.xaxis.set_major_formatter(mdates.DateFormatter("%m月%d日"))
            ax.xaxis.set_major_locator(mdates.DayLocator(interval=1))
            self.canvas2.draw()
        except:
            self.label_27.setText(_translate("Form", "未计算"))
            self.label_28.setText(_translate("Form", "未计算"))
            self.label_29.setText(_translate("Form", "未计算"))
            QMessageBox.warning(self, "错误", "误差分析失败")

    def fused_computing(self):
        if len(self.all_result) == 0:
            QMessageBox.warning(self, "错误", "请至少进行一次反演计算")
            return False
        try:
            mae_mean = np.mean(np.asarray(self.mae))
            rmse_mean = np.mean(np.asarray(self.rmse))
            r_mean = np.mean(np.asarray(self.r))
            self.label_27.setText(_translate("Form", "{:.3f}".format(mae_mean)))
            self.label_28.setText(_translate("Form", "{:.3f}".format(rmse_mean)))
            self.label_29.setText(_translate("Form", "{:.3f}".format(r_mean)))

            self.figure3.clear()
            self.canvas3.draw()
            QApplication.processEvents()
            ax = self.figure3.add_subplot(111)
            ax.set_title('海平面高度融合结果图')
            ax.set_xlabel('时间')
            ax.xaxis.set_major_formatter(mdates.DateFormatter("%m月%d日"))
            ax.xaxis.set_major_locator(mdates.DayLocator(interval=1))
            ax.set_ylabel('潮位 (m)')
            ax.grid(True)
            line1 = plt.Line2D([0], [0], color='gray', lw=1, label='真实潮位')
            line2 = plt.Line2D([0], [0], marker='$\u2605$', color='red', linestyle='', label='反演潮位')
            ax.legend(loc='upper left', handles=[line1, line2])
            ax.plot(self.real_time, self.real_high, '-', color=np.random.rand(3, ))
            colors = plt.cm.hsv(np.linspace(0, 0.8, len(self.all_result)))
            for i, result in enumerate(self.all_result):
                color = colors[i]
                inversion_time = [t[0].replace(second=0) for t in result['bbb1']]
                inversion_high = [h[2] for h in result['bbb1']]
                for i in range(len(inversion_time)):
                    ax.plot(inversion_time[i], inversion_high[i], marker='$\u2605$', color=color, markersize=5)
                    self.canvas3.draw()
                    QApplication.processEvents()
        except:
            self.label_27.setText(_translate("Form", "未计算"))
            self.label_28.setText(_translate("Form", "未计算"))
            self.label_29.setText(_translate("Form", "未计算"))
            self.all_result = []
            self.mae = []
            self.rmse = []
            self.r = []
            QMessageBox.warning(self, "错误", "融合计算失败")
            return False
        return True


if __name__ == "__main__":
    app = QApplication([])
    window = MyApp()
    window.show()
    app.exec_()
